iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
Software Development

Java 17 新登場系列 第 6

Day 6 - 串流操作 3

  • 分享至 

  • xImage
  •  

使用 anyMatch、 allMatch、noneMatch

這三個方法也是非常簡單 anyMatch、allMatch 、 noneMatch 方法的簽名如下:

boolean anyMatch(Predicate<? super T> predicate)
boolean allMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)

直接來看幾個例子:

public class Primes {
    public boolean isPrime(int num) {
        int limit = (int) (Math.sqrt(num) + 1);
        return num == 2 || num > 1 && IntStream.range(2, limit)
               .noneMatch(divisor -> num % divisor == 0);
    }
}

IntStream.of(2, 3, 5, 7, 11, 13, 17, 19)
        .allMatch(calculator::isPrime)); //true
Stream.of(4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20)
        .anyMatch(calculator::isPrime));// false

如果是空的串流,對於 allMatch、noneMatch 都是 true:

Stream.empty().allMatch(e -> false); //true
Stream.empty().noneMatch(e -> true); //true
Stream.empty().anyMatch(e -> true);  //false

串流 flatMap vs. map

先看這兩個方法的簽章

<R> Stream<R> map(Function<? super T,? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

map 沒啥問題,已經用很多了,flatMap 主要用在串流物件裡面還有 nested object list 的時候,我們可以利用 flatMap 一次拿到所有串流物件的 nested object list ,是個實用的方法

public class Customer {
    private String name;
    private List<Order> orders = new ArrayList<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() { return name; }
    public List<Order> getOrders() { return orders; }

    public Customer addOrder(Order order) {
        orders.add(order);
        return this;
    }
}

public class Order {
    private int id;

    public Order(int id) {
        this.id = id;
    }

    public int getId() { return id; }
}

//init data
Customer sheridan = new Customer("Sheridan");
Customer ivanova = new Customer("Ivanova");
Customer garibaldi = new Customer("Garibaldi");

sheridan.addOrder(new Order(1))
        .addOrder(new Order(2))
        .addOrder(new Order(3));
ivanova.addOrder(new Order(4))
        .addOrder(new Order(5));

List<Customer> customers = Arrays.asList(sheridan, ivanova, garibaldi);

Stream<List<Order>> streamListOrders 
                      = customers.stream()
                                  .map(customer -> customer.getOrders().stream());
streamListOrders.forEach(System.out::println);                                    

Stream<Order> streamOrders 
                      = customers.stream()
                                  .flatMap(customer -> customer.getOrders().stream());
streamOrders.forEach(System.out::println);

//output:
java.util.stream.ReferencePipeline$Head@2a3046da
java.util.stream.ReferencePipeline$Head@5cbc508c
java.util.stream.ReferencePipeline$Head@3419866c
Order{id=1}
Order{id=2}
Order{id=3}
Order{id=4}
Order{id=5}

如果只是使用 map 沒辦法直接得到 List

串接串流

我們可以使用 Stream interface 定義的 concat 方法來實現流的串接,簽章如下:

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)

範例:

Stream<String> first = Stream.of("a", "b", "c").parallel();
Stream<String> second = Stream.of("X", "Y", "Z");
List<String> strings = Stream.concat(first, second) ➊
        .collect(Collectors.toList());
System.out.println(strings);
//output:
[a, b, c, X, Y, Z]

串流惰性特性

串流是惰性的,在達到終止條件前不會處理元素,達到終止條件後才透過管線逐一處理每個元素。

下面這個例子特別從 100 開始產生無限串流,findFirst() 是終止條件

example 1: 輸出過程訊息,是個串流的過程 & 第一個被三整除的數: 204

example 2: 拿掉 findFirst() 後沒有任何輸出

int multByTwo(int n) {
    System.out.printf("Inside multByTwo with arg %d%n", n);
    return n * 2;
}

boolean divByThree(int n) {
    System.out.printf("Inside divByThree with arg %d%n", n);
    return n % 3 == 0;
}

//example 1
Optional<Integer> result = Stream.iterate(100, i -> i + 2)
    .map(this::multByTwo)
    .filter(this::divByThree)
    .findFirst();
System.out.println(result);

//output:
Inside multByTwo with arg 100
Inside divByThree with arg 200
Inside multByTwo with arg 102
Inside divByThree with arg 204
Optional[204]

Stream.iterate(100, i -> i + 2)
    .map(this::multByTwo)
    .filter(this::divByThree);
//output:
(empty)

串流操作與以往的集合式編程很不一樣,使用起來還是有那麼一些不習慣,我們可以藉由大量練習 & 實作來熟悉這個強大的工具,不僅僅是語法上的進步,在觀念以及執行效能上也可能帶來影響

參考資料:

Java 8 - 輕鬆解決 8 與 9 的難題(O’REILLY)
https://geek-docs.com/java/java-examples/java-inert-flow.html


上一篇
Day 5 - 串流操作 2
下一篇
Day 7 - 比較器 & 集合
系列文
Java 17 新登場8
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言